package com.sktk.keepAccount.aop;

import com.sktk.keepAccount.annotation.RequestLimit;
import com.sktk.keepAccount.utils.IPUtils;
import com.sktk.keepAccount.common.core.exception.BaseException;
import com.sktk.keepAccount.common.core.exception.SystemErrorType;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class RequestLimitAspect {

    private static final Logger logger = LoggerFactory.getLogger(RequestLimitAspect.class);

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    // @Before可以有两者写法, @annotation(形参test)
    @Before("@annotation(requestLimit)")//
    public void doBefore(JoinPoint joinPoint, RequestLimit requestLimit) throws Throwable {

        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(
                RequestContextHolder.getRequestAttributes())).getRequest();
        if (request == null) {
            throw new BaseException(SystemErrorType.QPS_LIMIT);
        }
        String ip = IPUtils.getClientAddress(request);
        String url = request.getRequestURL().toString();
        String key = "req_limit_".concat(url).concat(ip);
        long count = redisTemplate.opsForValue().increment(key, 1);
        if (count == 1) {
            redisTemplate.expire(key, requestLimit.time(), TimeUnit.MILLISECONDS);
        }
        if (count > requestLimit.count()) {
            logger.info("用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + requestLimit.count() + "]");
            throw new BaseException(SystemErrorType.QPS_LIMIT);
        }
    }

}

